import email
import imaplib
import poplib
from email.message import Message
from email.parser import Parser

imaplib.Commands["ID"] = ("AUTH",)


class Pop3Server:
    def __init__(self, email, password, host="pop.qq.com"):
        if ':' in host:
            host, port = host.split(":")
            if port == '995':
                self.server = poplib.POP3_SSL(host)
            else:
                self.server = poplib.POP3(host)
        else:
            self.server = poplib.POP3(host)

        # open debug
        self.server.set_debuglevel(0)

        # 身份验证
        self.server.user(email)
        self.server.pass_(password)

    def __enter__(self):
        return self

    def __del__(self):
        self.server.close()

    def __exit__(self, exc_type, exc_val, exc_tb):
        ...

    @classmethod
    def get_email(cls, email, password, host="pop.qq.com", index=None):
        with Pop3Server(email, password, host) as server:
            for email in server.email_generator(index):
                return email

    def email_generator(self, index=None):
        resp, mails, octets = self.server.list()

        if len(mails) < 1:
            return None

        max_length = index or len(mails)

        for i in range(max_length, 0, -1):
            resp, lines, octets = self.server.retr(i)

            # 可以获得整个邮件的原始文本:
            msg_content = b'\r\n'.join(lines).decode('utf-8')
            # 解析出邮件:

            msg = Parser().parsestr(msg_content)
            msg_info = {k: v for k, v in msg.items()}
            msg_info['text'] = Pop3Server.get_mail_content(msg)
            msg_info['msg_object'] = msg
            yield msg_info

    @staticmethod
    def get_mail_content(msg):
        if msg == None:
            return None
        for _type, text in Pop3Server.mail_details_generator(msg):
            if _type == 'text':
                return text

    @staticmethod
    def mail_details_generator(msg):
        if msg == None:
            yield None
        else:
            if not isinstance(msg, Message) and msg.get("msg_object"):
                msg = msg['msg_object']
            for part in msg.walk():
                if part.get_filename():
                    data = part.get_payload(decode=True)
                    yield "file", [part.get_filename(), data, part.get_content_type()]
                elif not part.is_multipart():
                    data = part.get_payload(decode=True)
                    try:
                        yield "text", data.decode()
                    except Exception as e:
                        yield "text", "最新邮件不是文本邮件"


class IMAPServer:
    imap_host_map = {
        "outlook.com": "outlook.office365.com",
        "hotmail.com": "outlook.office365.com",
        "yeah.net": "imap.yeah.net",
        "126.com": "imap.126.com",
        "163.com": "imap.163.com",
        "qq.com": "imap.qq.com",
        "sohu.com": "imap.sohu.com",
        "sina.com": "imap.sina.com",
    }

    def __init__(self, email, password):
        host = self.imap_host_map[email.split("@")[-1]]
        if ":" in host:
            imap_host, imap_port = host.split(":")
            self.server = imaplib.IMAP4(imap_host, int(imap_port))
        else:
            self.server = imaplib.IMAP4_SSL(host)

        self.server.login(email, password)
        if host in [
            "imap.126.com",
            "imap.163.com",
            "imap.yeah.net"
        ]:
            args = ("name", "finance", "contact", email, "version", "1.0.0", "vendor", "myclient")
            typ, dat = self.server._simple_command('ID', '("' + '" "'.join(args) + '")')
            ...

    def __del__(self):
        # self.server.select("Inbox")
        # self.server.logout()
        """"""

    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.__del__()

    def select(self, s: str):
        return self.server.select(self.encode(s))

    def decode(self, s: bytes):
        return s.decode().replace("&", "+").encode().decode("utf-7")

    def encode(self, s: str):
        return s.encode("utf-7").decode().replace("+", "&")

    def email_generator(self, _type="ALL", *search):
        """
        since_date = time.strftime("%d-%b-%Y", time.localtime(time.time() - 24 * 60 * 60 * 30))
        'ALL', 'SINCE', since_date,'FROM', "accounts@fruugo.com"
        """
        result, data = self.server.search(None, _type, *search)

        for num in data[0].split(b" ")[::-1]:
            if not num:
                break
            result, data = self.server.fetch(num, '(RFC822)')
            raw_email = data[0][1]
            msg = email.message_from_bytes(raw_email)
            msg_info = {k: v for k, v in msg.items()}
            msg_info['text'] = IMAPServer.get_mail_content(msg)
            msg_info['msg_object'] = msg
            yield msg_info

    def folder_list(self):
        status, folder_list = self.server.list()

        if status == "OK":
            for folder in folder_list:
                if folder is not None and isinstance(folder, bytes):
                    f = folder.split(b' "/" ')[-1]
                    yield self.decode(f)

    get_mail_content = Pop3Server.get_mail_content
    mail_details_generator = Pop3Server.mail_details_generator


if __name__ == '__main__':
    import time,datetime

    with IMAPServer("zhantanyui@163.com", "BOSMRLSOLLYTFQTG") as server:
        results = server.select("Inbox")
        # since_date = time.strftime("%d-%b-%Y", time.localtime(time.time() - 24 * 60 * 60 * 190))
        for msg in server.email_generator("ALL"):
            if msg['From'] != "accounts@fruugo.com":
                continue
            mail_date = msg['Date']
            ts = datetime.datetime.strptime(mail_date, "%a, %d %b %Y %H:%M:%S %z").timestamp()
            if time.time() - ts > 24 * 60 * 60 * 90:
                continue
            for _type, data in IMAPServer.mail_details_generator(msg):
                if _type == "file":
                    print(data[0], msg['Date'])
                # if _type == "file" and MATCH_FILENAME.match(data[0]):
                #     push_file(email, ts, *data)
